#include "ObjectManager.hpp"

ObjectManager::ObjectManager(){
    size = 0;
}

/**
 * Initialize object manager.
 * Loads environment manager and provided script.
 * Runs the init script in provided script.
 * @param script Path to script to load.
 */
void ObjectManager::init(const char* script){
    scriptEngine.registerClass(this);
    scriptEngine.loadScript("Objects/objectmanager.lua");
	scriptEngine.loadScript(script);
    
    //Run manager initialization script
    runScript("init", this);
}

/**
 * Register a scriptable object that can be used by the object manager.
 * This is a wrapper for ScriptEngine::registerClass.
 * See specific implementations of ObjectManager for object lua naming info.
 * @param object Object to register.
 */
void ObjectManager::registerObject(Scriptable* object){
    scriptEngine.registerClass(object);
}

/**
 * Register an object as a global in all environments in the manager.
 * An object cannot be registerred before the init call has been made.
 * @param name Name of global.
 * @param object Object to register.
 */
void ObjectManager::registerGlobal(const char* name, Scriptable* object){
    registerObject(object);
    scriptEngine.loadFunction("registerGlobal");
    scriptEngine.pushString(name);
    scriptEngine.pushScriptable(object);
    scriptEngine.run(2, 0);
}

/**
 * Load an object script into available scripts list.
 * @param name Name of script to load.
 */
void ObjectManager::loadScript(const char* name){
    if(name && strlen(name) != 0){
        scriptEngine.loadFunction("loadScript");
        scriptEngine.pushString(name);
        scriptEngine.run(1, 0);
    }
}

/**
 * Run a script on the ObjectManager with given name and objects as args.
 * @param script Name of script function.
 */
void ObjectManager::runScript(const char* script, Scriptable* o1, Scriptable* o2){
    scriptEngine.loadFunction(script);
	scriptEngine.pushScriptable(o1);
    scriptEngine.pushScriptable(o2);
	scriptEngine.run(2, 0);
}

/**
 * Run a script on the ObjectManager with given name and object as arg.
 * @param script Name of script function.
 * @param object Object to pass as an arg.
 */
void ObjectManager::runScript(const char* script, Scriptable* object){
    scriptEngine.loadFunction(script);
	scriptEngine.pushScriptable(object);
	scriptEngine.run(1, 0);
}

/**
 * Run startup script of Manager script.
 * If resolving the script fails hasScript for the object will be set to false.
 * @param object Object created.
 * @param name Object type name.
 */
void ObjectManager::runStartup(BaseObject* object, const char* name){
    if(name && strlen(name) != 0){
        scriptEngine.loadFunction("startup");
        scriptEngine.pushScriptable(object);
        scriptEngine.pushString(name);
        scriptEngine.run(2, 0);
    }else{
        object->hasScript = false;
    }
}

/**
 * Run object's update script method.
 * This method includes the checks to see if the run script should be called and
 * therefore this method should simply be called on any existing object..
 * Checks Include: object::hasScript object::updateable, object::destroy.
 */
void ObjectManager::runUpdate(BaseObject* object){
	if(object->hasScript && object->updateable && !object->destroy)
		runScript("update", object);
}

/**
 * Run object's destroy script method.
 */
void ObjectManager::runDestroy(BaseObject* object){
	if(object->hasScript)
        runScript("destroy", object);
}